import java.util.concurrent.Exchanger;

/**
 * Created by admin on 2019/1/17.
 */

public class ExchangerDemo {
    public static void main(String[] args) {
        final Exchanger exchanger = new Exchanger();
        new Thread(new Runnable() {
            String from = "湖人";
            String data = "克拉克森，小拉里南斯";
            public void run() {
                nbaTrade(from,data, exchanger);
            }
        }).start();

        new Thread(new Runnable() {
            String from = "骑士";
            String data = "以赛亚托马斯，弗莱";
            public void run() {
                nbaTrade(from,data, exchanger);
            }
        }).start();
    }

    private static void nbaTrade(String from, String data, Exchanger exchanger) {
        try {
            System.out.println(from + "把 " + data + " 交易出去");
            Thread.sleep((long) (Math.random() * 1000));
            String data2 = (String) exchanger.exchange(data);
            System.out.println(from + "交易得到" + data2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
















//    private final Object slotExchange(Object item, boolean timed, long ns) {
//        // 得到一个初试的Node
//        Node p = participant.get();
//        // 当前线程
//        Thread t = Thread.currentThread();
//        // 如果发生中断，返回null,会重设中断标志位，并没有直接抛异常
//        if (t.isInterrupted()) // preserve interrupt status so caller can recheck
//            return null;
//
//        for (Node q;;) {
//            // 槽位 solt不为null,则说明已经有线程在这里等待交换数据了
//            if ((q = slot) != null) {
//                // 重置槽位
//                if (U.compareAndSwapObject(this, SLOT, q, null)) {
//                    //获取交换的数据
//                    Object v = q.item;
//                    //等待线程需要的数据
//                    q.match = item;
//                    //等待线程
//                    Thread w = q.parked;
//                    //唤醒等待的线程
//                    if (w != null)
//                        U.unpark(w);
//                    return v; // 返回拿到的数据，交换完成
//                }
//                // create arena on contention, but continue until slot null
//                //存在竞争，其它线程抢先了一步该线程，因此需要采用多槽位模式，这个后面再分析
//                if (NCPU > 1 && bound == 0 &&
//                        U.compareAndSwapInt(this, BOUND, 0, SEQ))
//                    arena = new Node[(FULL + 2) << ASHIFT];
//            }
//            else if (arena != null) //多槽位不为空，需要执行多槽位交换
//                return null; // caller must reroute to arenaExchange
//            else { //还没有其他线程来占据槽位
//                p.item = item;
//                // 设置槽位为p(也就是槽位被当前线程占据)
//                if (U.compareAndSwapObject(this, SLOT, null, p))
//                    break; // 退出无限循环
//                p.item = null; // 如果设置槽位失败，则有可能其他线程抢先了，重置item,重新循环
//            }
//        }
//
//        //当前线程占据槽位，等待其它线程来交换数据
//        int h = p.hash;
//        long end = timed ? System.nanoTime() + ns : 0L;
//        int spins = (NCPU > 1) ? SPINS : 1;
//        Object v;
//        // 直到成功交换到数据
//        while ((v = p.match) == null) {
//            if (spins > 0) { // 自旋
//                h ^= h << 1; h ^= h >>> 3; h ^= h << 10;
//                if (h == 0)
//                    h = SPINS | (int)t.getId();
//                else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0)
//                    // 主动让出cpu,这样可以提供cpu利用率（反正当前线程也自旋等待，还不如让其它任务占用cpu）
//                    Thread.yield();
//            }
//            else if (slot != p) //其它线程来交换数据了，修改了solt,但是还没有设置match,再稍等一会
//                spins = SPINS;
//                //需要阻塞等待其它线程来交换数据
//                //没发生中断，并且是单槽交换，没有设置超时或者超时时间未到 则继续执行
//            else if (!t.isInterrupted() && arena == null &&
//                    (!timed || (ns = end - System.nanoTime()) > 0L)) {
//                // cas 设置BLOCKER，可以参考Thread 中的parkBlocker
//                U.putObject(t, BLOCKER, this);
//                // 需要挂起当前线程
//                p.parked = t;
//                if (slot == p)
//                    U.park(false, ns); // 阻塞当前线程
//                // 被唤醒后
//                p.parked = null;
//                // 清空 BLOCKER
//                U.putObject(t, BLOCKER, null);
//            }
//            // 不满足前面 else if 条件，交换失败，需要重置solt
//            else if (U.compareAndSwapObject(this, SLOT, p, null)) {
//                v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
//                break;
//            }
//        }
//        //清空match
//        U.putOrderedObject(p, MATCH, null);
//        p.item = null;
//        p.hash = h;
//        // 返回交换得到的数据（失败则为null）
//        return v;
//    }
//
//
//
//    private final Object arenaExchange(Object item, boolean timed, long ns) {
//        // 槽位数组
//        Node[] a = arena;
//        //代表当前线程的Node
//        Node p = participant.get(); // p.index 初始值为 0
//        for (int i = p.index;;) {                      // access slot at i
//            int b, m, c; long j;                       // j is raw array offset
//            //在槽位数组中根据"索引" i 取出数据 j相当于是 "第一个"槽位
//            Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
//            // 该位置上有数据(即有线程在这里等待交换数据)
//            if (q != null && U.compareAndSwapObject(a, j, q, null)) {
//                // 进行数据交换，这里和单槽位的交换是一样的
//                Object v = q.item;                     // release
//                q.match = item;
//                Thread w = q.parked;
//                if (w != null)
//                    U.unpark(w);
//                return v;
//            }
//            // bound 是最大的有效的 位置，和MMASK相与，得到真正的存储数据的索引最大值
//            else if (i <= (m = (b = bound) & MMASK) && q == null) {
//                // i 在这个范围内，该槽位也为空
//
//                //将需要交换的数据 设置给p
//                p.item = item;                         // offer
//                //设置该槽位数据(在该槽位等待其它线程来交换数据)
//                if (U.compareAndSwapObject(a, j, null, p)) {
//                    long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
//                    Thread t = Thread.currentThread(); // wait
//                    // 进行一定时间的自旋
//                    for (int h = p.hash, spins = SPINS;;) {
//                        Object v = p.match;
//                        //在自旋的过程中，有线程来和该线程交换数据
//                        if (v != null) {
//                            //交换数据后，清空部分设置，返回交换得到的数据，over
//                            U.putOrderedObject(p, MATCH, null);
//                            p.item = null;             // clear for next use
//                            p.hash = h;
//                            return v;
//                        }
//                        else if (spins > 0) {
//                            h ^= h << 1; h ^= h >>> 3; h ^= h << 10; // xorshift
//                            if (h == 0)                // initialize hash
//                                h = SPINS | (int)t.getId();
//                            else if (h < 0 &&          // approx 50% true
//                                    (--spins & ((SPINS >>> 1) - 1)) == 0)
//                                Thread.yield();        // two yields per wait
//                        }
//                        // 交换数据的线程到来，但是还没有设置好match，再稍等一会
//                        else if (U.getObjectVolatile(a, j) != p)
//                            spins = SPINS;
//                            //符合条件，特别注意m==0 这个说明已经到达area 中最小的存储数据槽位了
//                            //没有其他线程在槽位等待了，所有当前线程需要阻塞在这里
//                        else if (!t.isInterrupted() && m == 0 &&
//                                (!timed ||
//                                        (ns = end - System.nanoTime()) > 0L)) {
//                            U.putObject(t, BLOCKER, this); // emulate LockSupport
//                            p.parked = t;              // minimize window
//                            // 再次检查槽位，看看在阻塞前，有没有线程来交换数据
//                            if (U.getObjectVolatile(a, j) == p)
//                                U.park(false, ns); // 挂起
//                            p.parked = null;
//                            U.putObject(t, BLOCKER, null);
//                        }
//                        // 当前这个槽位一直没有线程来交换数据，准备换个槽位试试
//                        else if (U.getObjectVolatile(a, j) == p &&
//                                U.compareAndSwapObject(a, j, p, null)) {
//                            //更新bound
//                            if (m != 0)                // try to shrink
//                                U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
//                            p.item = null;
//                            p.hash = h;
//                            // 减小索引值 往"第一个"槽位的方向挪动
//                            i = p.index >>>= 1;        // descend
//                            // 发送中断，返回null
//                            if (Thread.interrupted())
//                                return null;
//                            // 超时
//                            if (timed && m == 0 && ns <= 0L)
//                                return TIMED_OUT;
//                            break;                     // expired; restart 继续主循环
//                        }
//                    }
//                }
//                else
//                    //占据槽位失败，先清空item,防止成功交换数据后，p.item还引用着item
//                    p.item = null;                     // clear offer
//            }
//            else { // i 不在有效范围，或者被其它线程抢先了
//                //更新p.bound
//                if (p.bound != b) {                    // stale; reset
//                    p.bound = b;
//                    //新bound ，重置collides
//                    p.collides = 0;
//                    //i如果达到了最大，那么就递减
//                    i = (i != m || m == 0) ? m : m - 1;
//                }
//                else if ((c = p.collides) < m || m == FULL ||
//                        !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
//                    p.collides = c + 1; // 更新冲突
//                    // i=0 那么就从m开始，否则递减i
//                    i = (i == 0) ? m : i - 1;          // cyclically traverse
//                }
//                else
//                    //递增，往后挪动
//                    i = m + 1;                         // grow
//                // 更新index
//                p.index = i;
//            }
//        }
//    }
}
